package controllers.user;

import java.util.Collection;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import services.ProjectService;
import services.RegistrationService;
import services.UserService;
import services.WorkUpdateService;
import controllers.AbstractController;
import domain.Project;
import domain.Registration;
import domain.WorkUpdate;
import forms.ProjectForm;

@Controller
@RequestMapping("/project/user")
public class ProjectUserController extends AbstractController {

	// Services
	@Autowired
	private ProjectService projectService;
	@Autowired
	private UserService userService;
	@Autowired
	private RegistrationService registrationService;
	@Autowired
	private WorkUpdateService workUpdateService;

	// Constructors
	public ProjectUserController() {
		super();
	}

	// Listing methods
	// Not finished projects
	@RequestMapping(value = "/notFinishedList", method = RequestMethod.GET)
	public ModelAndView list() {
		ModelAndView result;
		Collection<Project> projects;

		projects = projectService.findNotFinishedProjects();

		result = new ModelAndView("project/notFinishedList");
		result.addObject("requestURI", "project/user/notFinishedList.do");
		result.addObject("projects", projects);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	// Available projects
	@RequestMapping(value = "/availableProjects", method = RequestMethod.GET)
	public ModelAndView availableList() {
		ModelAndView result;
		Collection<Project> projects;

		projects = projectService.findAvailableProjects();

		result = new ModelAndView("project/availableList");
		result.addObject("requestURI", "project/user/availableProjects.do");
		result.addObject("projects", projects);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	// Created projects
	@RequestMapping(value = "/createdProjects", method = RequestMethod.GET)
	public ModelAndView createdList() {
		ModelAndView result;
		Collection<Project> projects;

		projects = projectService.findCreatedProjects();

		result = new ModelAndView("project/createdList");
		result.addObject("requestURI", "project/user/createdProjects.do");
		result.addObject("projects", projects);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	// Joined projects
	@RequestMapping(value = "/joinedProjects", method = RequestMethod.GET)
	public ModelAndView joinedList() {
		ModelAndView result;
		Collection<Project> projects;

		projects = projectService.findJoinedProjects();

		result = new ModelAndView("project/joinedList");
		result.addObject("requestURI", "project/user/joinedProjects.do");
		result.addObject("projects", projects);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	// Followed projects
	@RequestMapping(value = "/followedProjects", method = RequestMethod.GET)
	public ModelAndView followedList() {
		ModelAndView result;
		Collection<Project> projects;

		projects = projectService.findFollowedProjects();

		result = new ModelAndView("project/followedList");
		result.addObject("requestURI", "project/user/followedProjects.do");
		result.addObject("projects", projects);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	// Creation
	@RequestMapping(value = "/create", method = RequestMethod.GET)
	public ModelAndView create() {
		ModelAndView result;
		ProjectForm projectForm;
		Project project;
		Boolean isNew;
		Boolean editable;
		Boolean isOwner;

		project = projectService.create();
		projectForm = projectService.projectToForm(project);
		isNew = true;
		editable = true;
		isOwner = true;

		result = new ModelAndView("project/create");
		result.addObject("projectForm", projectForm);
		result.addObject("requestURI", "project/user/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("editable", editable);
		result.addObject("isOwner", isOwner);
		result.addObject("backURI", "/welcome/index.do");

		return result;

	}

	// Edition
	@RequestMapping(value = "/edit", method = RequestMethod.GET)
	public ModelAndView edit(@RequestParam int projectId) {
		ModelAndView result;
		ProjectForm projectForm;
		Project project;
		Collection<WorkUpdate> workUpdates;
		Collection<Registration> registrations;
		Boolean hasVacancies;
		Boolean isNew;
		Boolean editable;
		Boolean isOwner;
		Boolean creating;
		Boolean recruiting;
		Boolean canJoin;
		Boolean started;
		Boolean joined;
		Boolean following;
		Boolean finished;

		project = projectService.findOne(projectId);
		projectForm = projectService.projectToForm(project);
		workUpdates = workUpdateService.findByProjectId(projectId);
		registrations = registrationService.findByProjectId(project.getId());

		isNew = false;
		editable = false;
		isOwner = project.getCreator().equals(userService.findByPrincipal());
		creating = project.getStatus().equals("Creating");
		hasVacancies = !project.getVacancies().isEmpty();
		recruiting = project.getStatus().equals("Recruiting");
		started = project.getStatus().equals("Started");
		canJoin = projectService.findAvailableProjects().contains(project);
		joined = project.getRegistrations().contains(
				registrationService.getRegistrationForProject(userService
						.findByPrincipal().getId(), projectId));
		following = project.getFollowers().contains(
				userService.findByPrincipal());
		finished = project.getStatus().equals("Finished");

		result = new ModelAndView("project/edit");
		result.addObject("projectForm", projectForm);
		result.addObject("workUpdates", workUpdates);
		result.addObject("registrations", registrations);
		result.addObject("requestURI", "project/user/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("editable", editable);
		result.addObject("hasVacancies", hasVacancies);
		result.addObject("isOwner", isOwner);
		result.addObject("creating", creating);
		result.addObject("recruiting", recruiting);
		result.addObject("started", started);
		result.addObject("finished", finished);
		result.addObject("canJoin", canJoin);
		result.addObject("joined", joined);
		result.addObject("following", following);
		result.addObject("projectId", projectId);
		result.addObject("backURI", "/welcome/index.do");

		return result;

	}

	@RequestMapping(value = "/edit", method = RequestMethod.POST)
	public ModelAndView save(@Valid ProjectForm projectForm,
			BindingResult binding) {
		ModelAndView result;
		Project project;
		Boolean isNew;
		Boolean editable;
		Boolean isOwner;
		
		result = new ModelAndView("project/create");

		if (binding.hasErrors()) {
			result = createEditModelAndView(projectForm);
		} else {
			try {
				project = projectService.reconstruct(projectForm);
				projectService.save(project);
				result = new ModelAndView("redirect:../../");

			} catch (Throwable oops) {

				result = createEditModelAndView(projectForm,
						"project.commit.error");
			}
		}
		isNew = true;
		editable = true;
		isOwner = true;
		result.addObject("projectForm", projectForm);
		result.addObject("requestURI", "project/user/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("editable", editable);
		result.addObject("isOwner", isOwner);
		result.addObject("backURI", "/welcome/index.do");

		return result;

	}

	// Status methods

	@RequestMapping(value = "/finishCreate", method = RequestMethod.GET)
	public ModelAndView finishCreate(@RequestParam int projectId) {
		ModelAndView result;
		ProjectForm projectForm;
		Project project;
		Collection<WorkUpdate> workUpdates;
		Boolean hasVacancies;
		Boolean isNew;
		Boolean editable;
		Boolean isOwner;
		Boolean creating;
		Boolean recruiting;
		Boolean canJoin;
		Boolean started;
		Boolean joined;
		Boolean following;

		project = projectService.findOne(projectId);

		projectService.finishCreate(project);

		projectForm = projectService.projectToForm(project);
		workUpdates = workUpdateService.findByProjectId(projectId);

		isNew = false;
		editable = false;
		isOwner = project.getCreator().equals(userService.findByPrincipal());
		creating = project.getStatus().equals("Creating");
		hasVacancies = !project.getVacancies().isEmpty();
		recruiting = project.getStatus().equals("Recruiting");
		started = project.getStatus().equals("Started");
		
		canJoin = projectService.findAvailableProjects().contains(project);
		
		joined = project.getRegistrations().contains(
				registrationService.getRegistrationForProject(userService
						.findByPrincipal().getId(), projectId));
		following = project.getFollowers().contains(
				userService.findByPrincipal());

		result = new ModelAndView("project/edit");
		result.addObject("projectForm", projectForm);
		result.addObject("workUpdates", workUpdates);
		result.addObject("requestURI", "project/user/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("editable", editable);
		result.addObject("hasVacancies", hasVacancies);
		result.addObject("isOwner", isOwner);
		result.addObject("creating", creating);
		result.addObject("recruiting", recruiting);
		result.addObject("started", started);
		result.addObject("canJoin", canJoin);
		result.addObject("joined", joined);
		result.addObject("following", following);
		result.addObject("projectId", projectId);
		result.addObject("backURI", "/welcome/index.do");

		return result;

	}

	@RequestMapping(value = "/finishProject", method = RequestMethod.GET)
	public ModelAndView finishProject(@RequestParam int projectId) {
		ModelAndView result;
		ProjectForm projectForm;
		Project project;
		Collection<WorkUpdate> workUpdates;
		Collection<Registration> registrations;
		Boolean hasVacancies;
		Boolean isNew;
		Boolean editable;
		Boolean isOwner;
		Boolean creating;
		Boolean recruiting;
		Boolean canJoin;
		Boolean started;
		Boolean joined;
		Boolean following;
		Boolean finished;

		project = projectService.findOne(projectId);

		projectService.finishProject(project);

		projectForm = projectService.projectToForm(project);
		workUpdates = workUpdateService.findByProjectId(projectId);
		registrations = registrationService.findByProjectId(project.getId());

		isNew = false;
		editable = false;
		isOwner = project.getCreator().equals(userService.findByPrincipal());
		creating = project.getStatus().equals("Creating");
		hasVacancies = !project.getVacancies().isEmpty();
		recruiting = project.getStatus().equals("Recruiting");
		started = project.getStatus().equals("Started");
		finished = project.getStatus().equals("Finished");
		canJoin = projectService.findAvailableProjects().contains(project);
		joined = project.getRegistrations().contains(
				registrationService.getRegistrationForProject(userService
						.findByPrincipal().getId(), projectId));
		following = project.getFollowers().contains(
				userService.findByPrincipal());

		result = new ModelAndView("project/edit");
		result.addObject("projectForm", projectForm);
		result.addObject("workUpdates", workUpdates);
		result.addObject("registrations", registrations);
		result.addObject("requestURI", "project/user/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("editable", editable);
		result.addObject("hasVacancies", hasVacancies);
		result.addObject("isOwner", isOwner);
		result.addObject("creating", creating);
		result.addObject("recruiting", recruiting);
		result.addObject("started", started);
		result.addObject("finished", finished);
		result.addObject("canJoin", canJoin);
		result.addObject("joined", joined);
		result.addObject("following", following);
		result.addObject("projectId", projectId);
		result.addObject("backURI", "/welcome/index.do");

		return result;

	}

	@RequestMapping(value = "/followProject", method = RequestMethod.GET)
	public ModelAndView followProject(@RequestParam int projectId) {
		ModelAndView result;
		ProjectForm projectForm;
		Project project;
		Collection<WorkUpdate> workUpdates;
		Collection<Registration> registrations;
		Boolean hasVacancies;
		Boolean isNew;
		Boolean editable;
		Boolean isOwner;
		Boolean creating;
		Boolean recruiting;
		Boolean canJoin;
		Boolean started;
		Boolean finished;
		Boolean joined;
		Boolean following;

		project = projectService.findOne(projectId);

		projectService.followProject(project);

		projectForm = projectService.projectToForm(project);
		workUpdates = workUpdateService.findByProjectId(projectId);
		registrations = registrationService.findByProjectId(project.getId());

		isNew = false;
		editable = false;
		isOwner = project.getCreator().equals(userService.findByPrincipal());
		creating = project.getStatus().equals("Creating");
		hasVacancies = !project.getVacancies().isEmpty();
		recruiting = project.getStatus().equals("Recruiting");
		started = project.getStatus().equals("Started");
		finished = project.getStatus().equals("Finished");
		canJoin = projectService.findAvailableProjects().contains(project);
		joined = project.getRegistrations().contains(
				registrationService.getRegistrationForProject(userService
						.findByPrincipal().getId(), projectId));
		following = project.getFollowers().contains(
				userService.findByPrincipal());

		result = new ModelAndView("project/edit");
		result.addObject("projectForm", projectForm);
		result.addObject("workUpdates", workUpdates);
		result.addObject("registrations", registrations);
		result.addObject("requestURI", "project/user/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("editable", editable);
		result.addObject("hasVacancies", hasVacancies);
		result.addObject("isOwner", isOwner);
		result.addObject("creating", creating);
		result.addObject("recruiting", recruiting);
		result.addObject("started", started);
		result.addObject("finished", finished);
		result.addObject("canJoin", canJoin);
		result.addObject("joined", joined);
		result.addObject("following", following);
		result.addObject("projectId", projectId);
		result.addObject("backURI", "/welcome/index.do");

		return result;

	}

	@RequestMapping(value = "/unfollowProject", method = RequestMethod.GET)
	public ModelAndView unfollowProject(@RequestParam int projectId) {
		ModelAndView result;
		ProjectForm projectForm;
		Project project;
		Collection<WorkUpdate> workUpdates;
		Collection<Registration> registrations;
		Boolean hasVacancies;
		Boolean isNew;
		Boolean editable;
		Boolean isOwner;
		Boolean creating;
		Boolean recruiting;
		Boolean canJoin;
		Boolean started;
		Boolean finished;
		Boolean joined;
		Boolean following;

		project = projectService.findOne(projectId);

		projectService.unfollowProject(project);

		projectForm = projectService.projectToForm(project);
		workUpdates = workUpdateService.findByProjectId(projectId);
		registrations = registrationService.findByProjectId(project.getId());

		isNew = false;
		editable = false;
		isOwner = project.getCreator().equals(userService.findByPrincipal());
		creating = project.getStatus().equals("Creating");
		hasVacancies = !project.getVacancies().isEmpty();
		recruiting = project.getStatus().equals("Recruiting");
		started = project.getStatus().equals("Started");
		finished = project.getStatus().equals("Finished");
		canJoin = projectService.findAvailableProjects().contains(project);
		joined = project.getRegistrations().contains(
				registrationService.getRegistrationForProject(userService
						.findByPrincipal().getId(), projectId));
		following = project.getFollowers().contains(
				userService.findByPrincipal());

		result = new ModelAndView("project/edit");
		result.addObject("projectForm", projectForm);
		result.addObject("workUpdates", workUpdates);
		result.addObject("registrations", registrations);
		result.addObject("requestURI", "project/user/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("editable", editable);
		result.addObject("hasVacancies", hasVacancies);
		result.addObject("isOwner", isOwner);
		result.addObject("creating", creating);
		result.addObject("recruiting", recruiting);
		result.addObject("started", started);
		result.addObject("finished", finished);
		result.addObject("canJoin", canJoin);
		result.addObject("joined", joined);
		result.addObject("following", following);
		result.addObject("projectId", projectId);
		result.addObject("backURI", "/welcome/index.do");

		return result;

	}

	// Ancillary methods
	protected ModelAndView createEditModelAndView(ProjectForm projectForm) {
		ModelAndView result;

		result = createEditModelAndView(projectForm, null);

		return result;
	}

	protected ModelAndView createEditModelAndView(ProjectForm projectForm,
			String message) {
		ModelAndView result;

		result = new ModelAndView("project/edit");

		result.addObject("projectForm", projectForm);
		result.addObject("message", message);

		return result;
	}

}
